#include "lcddevice.h"
#include "bmp.h"
#include <cmath>

extern "C"
{
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/mman.h>
    #include <sys/ioctl.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <string.h>
    #include <stdlib.h>
    #include <stdbool.h>
    #include <sys/stat.h>
    #include <stdio.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <linux/input.h>
    #include "linux/fb.h"
}
LcdDevice::LcdDevice(string devname)
{
    //打开lcd设备
    this->fd = open(devname.c_str(), O_RDWR);
    if(this->fd < 0) 
    {
        perror("open error");
    }
    //获取lcd设备信息	
    struct fb_var_screeninfo info;
    int ret  = ioctl(this->fd, FBIOGET_VSCREENINFO, &info);

    //打开触摸屏
    this->fd_ts=open("/dev/input/event0",O_RDWR);
	if(this->fd_ts==-1)
	{
		printf("打开触摸屏失败!\n");
	}
#ifdef ARM
    this->width=info.xres;
    this->heigth=info.yres;
#else
    this->width=info.xres_virtual;
    this->heigth=info.yres_virtual;
#endif
    this->pixbyte = info.bits_per_pixel/8;
    this->screen_size = this->width*this->heigth*this->pixbyte;
    
    printf("x:y--%d:%d\n", info.xres, info.yres);
    printf("x:y--%d:%d\n", info.xres_virtual, info.yres_virtual);
    //映射
    this->mptr = mmap(NULL, this->screen_size, 
                    PROT_READ|PROT_WRITE, MAP_SHARED, 
                    this->fd, 0);

    if(this->mptr == MAP_FAILED)
    {
        perror("映射失败");
    }
}

LcdDevice& LcdDevice::lcdInstance()
{
    static LcdDevice lcd;
    return lcd;
}

LcdDevice::~LcdDevice()
{
    if(this->mptr != MAP_FAILED)
    {
        munmap(this->mptr, this->screen_size);
    }
    if(this->fd > 0)
    {
        close(this->fd);
    }
}
//获取触摸屏坐标
void LcdDevice::get_xy(int *x, int *y){
    struct input_event myevent;	//定义结构体保存触摸屏坐标信息
	
	//多次读取，获取X坐标和Y坐标
	while(1)
	{
		//读取触摸屏坐标,sizeof--》求数据类型大小
		read(fd_ts,&myevent,sizeof(myevent));
		
		if(myevent.type==EV_ABS)	//判断是不是触摸屏绝对坐标事件
		{
			if(myevent.code==ABS_X)	//说明是X坐标
			{
				//*x=myevent.value;	//保存X坐标值
				*x=myevent.value*800/1024;
				//printf("ABS_X:%d\n",myevent.value);
			}
			if(myevent.code==ABS_Y)	//说明是Y坐标
			{
				//*y=myevent.value;	//保存Y坐标值
				*y=myevent.value*480/600;
				//printf("ABS_Y:%d\n",myevent.value);
			}
		}	
		if(myevent.type==EV_KEY && myevent.code==BTN_TOUCH && myevent.value==1)
		{
			break;
		}
	}
}
//设置某一个像素点颜色
void  LcdDevice::drawPoint(int x, int y,  unsigned int color){
    //用ptr保存绘制的开始位置
    unsigned int *ptr =( (unsigned int*)this->mptr) + y*this->width+x;
    ptr[0] = color;
}
//清屏
void LcdDevice::clear(unsigned int color){
    int w=this->width; 
    int h=this->heigth;
    unsigned int *ptr = (unsigned int *)this->mptr;
    
    int i=0,j=0;
    for(i=0; i<h; i++)
    for(j=0; j<w; j++)
    {
        ptr[i*w+j] = color;
    }
}
//绘制RGB数据
void LcdDevice::drawRgb(int x, int y, int w,int h,  const char *rgbData,int pixbyte)
{
    unsigned int *ptr = (unsigned int *)this->mptr + this->width*y+x;
    int i=0, j=0;
    for(i=0; i<h; i++)
    {
        for(j=0; j<w; j++)
        {
            memcpy(ptr+j+i*this->width, rgbData+(w*i+j)*pixbyte, 4);
        }
    }
}

void LcdDevice::drawcircle(int x, int y, int r, unsigned int color)
{
    LcdDevice& lcd = LcdDevice::lcdInstance();
    for(int m = 1; m <= r; m++)
    {
        int x1,x2,x3,x4,y1,y2,y3,y4;
        int i,j;
        int pow_r = m * m;    
        int y_last;
        for(x1 = x - m,y_last = y; x1 <= x; x1++)
        {
            y1 = y + sqrt(pow_r - (x1 - x)*(x1 -x));
            if(y1 - y_last > 1)
            {

                for(j = y_last ; j < (y1+y_last)/2; j++)
                { // add pixel from y_last to harf
                    lcd.drawPoint(x1 - 1,        j,    color);
                    lcd.drawPoint((x<<1) - x1 + 1,    j,    color);
                    lcd.drawPoint((x<<1) - x1 + 1,    (y<<1) -j,    color);
                    lcd.drawPoint(x1 - 1,        (y<<1) -j,    color);
                }
                for(j = (y1+y_last) / 2 ; j < y1; j++)
                { // add pixel from hart to y_now
                    lcd.drawPoint(x1,    j,    color);
                    lcd.drawPoint((x<<1) - x1,j,    color);
                    lcd.drawPoint((x<<1) - x1,(y<<1) -j,    color);
                    lcd.drawPoint(x1,    (y<<1) -j,    color);
                }
            } 
            lcd.drawPoint(x1,        y1,        color);
            lcd.drawPoint((x<<1) - x1,    y1,        color);
            lcd.drawPoint((x<<1) - x1,    (y<<1) -y1,    color);
            lcd.drawPoint(x1,    (y<<1) -y1,    color);
            y_last = y1;
        }
    }
}

void LcdDevice::drawFilledCircle(int x, int y, int r, unsigned int color)
{
    LcdDevice& lcd = LcdDevice::lcdInstance();
    
    for(int m = 0; m <= r; m++)  // 修改半径循环范围
    {
        int x1, y1, x2, y2;
        int i, j;
        int pow_r = m * m;
        int y_last;

        for (x1 = x - m, y_last = y + m; x1 <= x + m; x1++)  // 修改x1的循环范围
        {
            y1 = y + sqrt(pow_r - (x1 - x) * (x1 - x));
            y2 = y - sqrt(pow_r - (x1 - x) * (x1 - x));

            for (j = y2; j <= y1; j++)  // 修改y的循环范围
            {
                lcd.drawPoint(x1, j, color);
            }
            
            y_last = y1;
        }
    }
}

